package com.liuyjy.base.common.util;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.liuyjy.base.common.entity.PageResult;
import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Author liuyjy
 * @Date 2022/1/24 8:59
 * @Description: 实体转换
 **/
@Slf4j
public class ObjConvertUtil {


    private static ObjectMapper mapper = new ObjectMapper();

    static {
        // 转换为格式化的json
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        // 如果json中有新增的字段并且是实体类类中不存在的，不报错
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        // 下面配置解决LocalDateTime序列化的问题
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        //日期序列化
//        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
//        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
//        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
//
//        //日期反序列化
//        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
//        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
//        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));

        mapper.registerModule(javaTimeModule);
    }

    /**
     * 获取ObjectMapper
     *
     * @return ObjectMapper
     */
    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    /**
     * 对象转String
     *
     * @param input 对象
     * @return JSONObject
     */
    public static <T> String convert(T input) {
        if (EmptyUtil.isEmpty(input)) {
            return null;
        }
        try {
            return mapper.writeValueAsString(input);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换字符串（String）过程失败，输入对象: {}", input, e);
        }
        return null;
    }

    /**
     * 字符串转对象
     *
     * @param str   JSON
     * @param clazz 对象
     * @return T
     */
    public static <T> T convert(String str,Class<T> clazz) {
        if (EmptyUtil.isEmpty(str)) {
            return null;
        }
        try {
            return mapper.readValue(str,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", str, e);
        }

        return null;
    }
    /**
     * 字符串转对象
     *
     * @param str JSON
     * @return T
     */
    public static <T> T convert(String str,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(str)) {
            return null;
        }
        try {
            return mapper.readValue(str,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", str, e);
        }

        return null;
    }
    /**
     * 字符串转对象
     *
     * @param src   JSON
     * @param typeReference 对象
     * @return T
     */
    public static <T> T convert(Reader src,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(Reader src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(InputStream src,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(InputStream src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(byte[] src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(byte[] src,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(File src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(File src,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(URL src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(URL src,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(DataInput src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValue(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> T convert(DataInput src,JavaType javaType) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            //JavaType javaType = mapper.getTypeFactory().constructType(clazz);
            return mapper.readValue(src,javaType);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> MappingIterator<T> convert(JsonParser src, Class<T> clazz) {
        if (EmptyUtil.isEmpty(src)) {
            return null;
        }
        try {
            return mapper.readValues(src,clazz);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        } catch (IOException e) {
            //throw new RuntimeException(e);
            log.error("Jackson转换对象失败，输入JSON: {}", src, e);
        }

        return null;
    }
    public static <T> MappingIterator<T> convert(JsonParser str,TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(str)) {
            return null;
        }
        try {
            return mapper.readValues(str,typeReference);
        } catch (JsonProcessingException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", str, e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return null;
    }


    /**
     * @param input 输入集合
     * @param clzz  输出集合类型
     * @param <E>   输入集合类型
     * @param <T>   输出集合类型
     * @return 返回集合
     */
    public static <E, T> T convert(E input, Class<T> clzz) {
        if (EmptyUtil.isEmpty(input)) {
            return null;
        }
        try {
            return mapper.convertValue(input, clzz);
        } catch (IllegalArgumentException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", input, e);
        }

        return null;
    }


    /**
     * new TypeReference<T>() {}
     *
     * @param input 输入集合
     * @param <E>   输入集合类型
     * @param <T>   输出集合类型
     * @return 返回集合
     */
    public static <E, T> T convert(E input, TypeReference<T> typeReference) {
        if (EmptyUtil.isEmpty(input)) {
            return null;
        }
        try {
            return mapper.convertValue(input,typeReference);
        } catch (IllegalArgumentException e) {
            log.error("Jackson转换对象失败，输入JSON: {}", input, e);
        }

        return null;
    }


    public static <T> List<Map<String, Object>> objToMap(List<T> input) {
        if (EmptyUtil.isEmpty(input)) {
            return null;
        }
        TypeReference<List<Map<String, Object>>> typeReference = new TypeReference<List<Map<String, Object>>>() {
        };
        return convert(input, typeReference);
    }

    public static <T> List<T> mapToObj(List<Map<String, Object>> map, Class<T> clzz) {
        if (EmptyUtil.isEmpty(map)) {
            return null;
        }
        TypeReference<List<T>> typeReference = new TypeReference<List<T>>() {
        };
        return convert(map, typeReference);
    }

    /**
     * @param input 输入集合
     * @param clzz  输出集合类型
     * @param <E>   输入集合类型
     * @param <T>   输出集合类型
     * @return 返回集合
     */
    public static <E, T> List<T> convert(List<E> input,Class<T> clzz) {
        List<T> output = new ArrayList<>();
        if (EmptyUtil.isEmpty(input)) {
            return output;
        }
        for (E e : input) {
            T convert = convert(e, clzz);
            output.add(convert);
        }
        return output;
//        JavaType javaType=mapper.constructType(output.getClass());
//        return mapper.convertValue(input,javaType);
    }
    /**
     * @param input 输入集合
     * @param clzz  输出集合类型
     * @param <E>   输入集合类型
     * @param <T>   输出集合类型
     * @return 返回集合
     */
    public static <E, T> Set<T> convert(Set<E> input,Class<T> clzz) {
        Set<T> output = new HashSet<>();
        if (EmptyUtil.isEmpty(input)) {
            return output;
        }

//        JavaType javaType=mapper.constructType(output.getClass());
//        return mapper.convertValue(input,javaType);
        for (E e : input) {
            T convert = convert(e, clzz);
            output.add(convert);
        }
        return output;
    }

    /**
     * @param page 输入集合
     * @param <T>  输出集合类型
     * @return 返回集合
     */
    public static <T> PageResult<T> convert(Page<T> page) {
        return PageResult.getPageResult(page, page.getRecords());
    }

    /**
     * @param page 输入集合
     * @param clzz 输出集合类型
     * @param <E>  输入集合类型
     * @param <T>  输出集合类型
     * @return 返回集合
     */
    public static <E, T> PageResult<T> convert(Page<E> page, Class<T> clzz) {
        List<E> input = page.getRecords();
        if (EmptyUtil.isEmpty(input)) {
            return PageResult.getPageResult(page,new ArrayList<>());
        }
        List<T> output =convert(input,clzz);
        return PageResult.getPageResult(page, output);
    }

    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("theonefx");
        user.setCreateTime(LocalDateTime.now());
        User user2 = new User();
        user2.setAge(182);
        user2.setName("theonefx2");
        user2.setCreateTime(LocalDateTime.now());
        List<User> list = new ArrayList<>();
        list.add(user);
        list.add(user2);
        User user3 = new User();
        user3.setUserList(list);
        System.out.println("list=" + list);

        User2 user21 = convert(user3, User2.class);
        System.out.println("user21=" + user21);

        JSONObject userJson = convert(user21, JSONObject.class);
        System.out.println("userJson=" + userJson);

//        String mapStr = convert(list);
//        System.out.println("mapStr=" + mapStr);
        List<User2> mapListNew = convert(list, User2.class);
        System.out.println("mapListNew=" + mapListNew);

        List<Map> listMap = convert(list,Map.class);
        System.out.println("listMap=" + listMap);

        String listStr = convert(list);
        System.out.println("listStr=" + listStr);
        List<User2> listStrList =new ArrayList<>();
        JSONArray jsonObject = convert(listStr,JSONArray.class);
        System.out.println("jsonObject=" + jsonObject);

        List<User> listUser = convert(listMap,User.class);
        System.out.println("listUser=" + listUser);

        //TypeReference<JSONArray> typeReference1=new TypeReference<JSONArray>() {};
        TypeReference<JSONArray> typeReference1=new TypeReference<JSONArray>() {};
        JSONArray convertMap = convert(mapListNew,typeReference1);
        System.out.println("convertUser=" + convertMap);


        TypeReference<List<Map<String, Object>>> typeReference=new TypeReference<List<Map<String, Object>>>() {};
        List<Map<String, Object>> mapList = convert(convertMap,typeReference);

        System.out.println("convertJson=" + mapList);
    }
}


@Data
@ToString
 class User {

    private String name;

    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
//    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
//    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime createTime = LocalDateTime.now();

    private List<User> userList;
}
@Data
@ToString
class User2 {

    private String name;

    private Integer age;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
//    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
//    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime createTime = LocalDateTime.now();

    private List<User2> userList;
}
